﻿// owner 蒋家伟

#include "TaskManager.h"

// std
#include <atomic>

// qt
#include <QTime>

// jsdk
#include "ITask.h"
#include "TaskGroup.h"
#include "Dbg_Warn_Define.h"
#include "ITaskDescription.h"
#include "ITaskExectutable.h"
#include "TaskTransfer.h"
#include "TaskEventArgs.h"
#include "TaskEvent.h"
#include "StringUtils.h"

using namespace jsdk;

namespace
{
    static TaskManager s_TaskManagerImp;
}

TaskManager& jsdk::TaskManager::get()
{
    return s_TaskManagerImp;
}

jsdk::TaskManager::TaskManager()
{
    TaskEvent::get().registerHandler(this);
    s_TaskManager = this;
}

jsdk::TaskManager::~TaskManager()
{
    s_TaskManager = nullptr;
    TaskEvent::get().unRegisterHandler(this);
}

bool jsdk::TaskManager::registerTaskExctutable(const std::wstring & taskDescription, TaskTaskExectutableCreator taskExectutableCreator)
{
    return m_taskDescriptionToExectutableMap.insert(std::make_pair(taskDescription, taskExectutableCreator)).second;
}

OwnerPtr<ITaskExectutable> jsdk::TaskManager::getTaskExectutable(const ITaskDescription& taskDescription)
{
    const std::wstring& description = taskDescription.getDescription();
    auto& iter = m_taskDescriptionToExectutableMap.find(description);
    if (iter != m_taskDescriptionToExectutableMap.end())
    {
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(iter->second.operator bool(), L"当前创建任务执行者的函数未初始化，请查看是否使用宏定义注册，详情见TaskRegisterHelper.h", L"蒋家伟", L"2023-08-21");
        return iter->second();
    }
    return nullptr;
}

std::vector<ITask*> jsdk::TaskManager::getAllTaskWithoutDelayTime()
{
    std::vector<ITask*> res;
    {
        std::unique_lock<std::mutex> ulock(m_taskMutex);
        for (auto& iter : m_taskIdToTaskList)
        {
            DBG_WARN_AND_CONTINUE_UNLESS(iter.second, L"存在空任务", L"蒋家伟", L"2023-08-17");
            if (!iter.second->hasDelayTime())
            {
                res.push_back(iter.second.get());
            }
        }
        ulock.unlock();
    }

    return res;
}

TaskId jsdk::TaskManager::getAvailableTaskId()
{
    static std::atomic<size_t> atomic_taskId = 1;
    return TaskId(atomic_taskId++);
}

OwnerPtr<ITask> jsdk::TaskManager::getTaskById(const TaskId& taskId)
{
    auto& iter = m_taskIdToNotifiedTaskList.find(taskId);
    if (iter == m_taskIdToNotifiedTaskList.end())
        return nullptr;

    OwnerPtr<ITask> opTask = nullptr;
    {
        std::unique_lock<std::mutex> ulock(m_taskMutex);
        opTask.swap(m_taskIdToNotifiedTaskList[taskId]);
        m_taskIdToNotifiedTaskList.erase(taskId);
        ulock.unlock();
    }

    return std::move(opTask);
}

TaskId jsdk::TaskManager::addAsyncTask(OwnerPtr<ITask> opTask)
{
    DBG_WARN_AND_RETURN_UNLESS(opTask, TaskId::s_InvalidTaskId, L"向管理器传递一个无效任务", L"蒋家伟", L"2023-07-31");

    TaskId taskId = TaskId(jsdk::TaskManager::getAvailableTaskId());
    opTask->setTaskId(taskId);

    bool hasDelayTime = opTask->hasDelayTime();
    {
        QTime currentTime;
        currentTime.start();
        std::unique_lock<std::mutex> ulock(m_taskMutex);
        ITask* pTempTask = opTask.get();    // 先记录一个临时地址，防止move后为空
        m_taskIdToTaskList.insert(std::make_pair(taskId, std::move(opTask)));
        if (hasDelayTime)
        {
            // 计算由于加锁消耗的时间，对其进行补偿
            // 如果加锁时间过长，或者延迟时间过短导致此任务在通知的时候并未放置到通知队列中，此任务将无法正确执行。
            // 因此，做时间的补偿保障任务的触发。
            uint32_t delayTime = static_cast<uint32_t>(currentTime.elapsed());
            uint32_t sourceDelayTime = pTempTask->getDelayTime();
            pTempTask->setDelayTime((sourceDelayTime > delayTime) ? sourceDelayTime - delayTime : 0);
            pTempTask->startTimer();
        }
        ulock.unlock();
    }

    if (!hasDelayTime)
    {
        TaskTransfer* pTaskTransfer = TaskTransfer::get();
        DBG_WARN_AND_RETURN_UNLESS(pTaskTransfer, TaskId::s_InvalidTaskId, L"任务分发器未初始化", L"蒋家伟", L"2023-07-31");
        pTaskTransfer->taskReady();
    }

    return taskId;
}

void jsdk::TaskManager::addSyncTask(OwnerPtr<ITask> opTask)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(opTask, L"向管理器传递一个无效任务", L"蒋家伟", L"2023-07-31");
    opTask->setTaskId(TaskManager::getAvailableTaskId());
    bool hasDelayTime = opTask->hasDelayTime();
    if (!hasDelayTime)
    {
        if (TaskGroup* pTaskGroup = dynamic_cast<TaskGroup*>(opTask.get()))
        {
            for (auto& iter : pTaskGroup->transformOwnShip())
            {
                iter->setTaskId(TaskManager::getAvailableTaskId());
                iter->exctue();
            }
        }
        else
        {
            opTask->exctue();
        }
    }
    else
    {
        // 在当前同步线程中起一个定时器，尽可能保障延迟时间的稳定。但这个导致线程不安全，需要使用者注意。
        DBG_WARN(L"警告 : 同步任务不应该设置延迟,但此次延迟依然生效", L"蒋家伟", L"2023-10-30");
        ITask* pTask = opTask.release();
        QTimer::singleShot(pTask->getDelayTime(), Qt::PreciseTimer, [pTask]() {
            OwnerPtr<ITask> topTask(pTask);
            DBG_WARN_AND_RETURN_VOID_UNLESS(topTask, L"同步延迟任务指针为空", L"蒋家伟", L"2023-09-13");
            topTask->exctue();
        });
    }
}

void jsdk::TaskManager::On(const IArgs * pArgs)
{
    const TaskEventArgs* pTaskEventArgs = dynamic_cast<const TaskEventArgs*>(pArgs);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pTaskEventArgs, L"当前事件非任务事件", L"蒋家伟", L"2023-08-17");
    const TaskId& taskId = pTaskEventArgs->getTaskId();
    if (pTaskEventArgs->getEventType() == TaskEventType::DelayTaskTrigger)
    {
        TaskTransfer* pTaskTransfer = TaskTransfer::get();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pTaskTransfer, L"任务分发器未初始化", L"蒋家伟", L"2023-07-31");
        pTaskTransfer->taskReady(taskId);
    }
    else if (pTaskEventArgs->getEventType() == TaskEventType::TaskNotified)
    {
        std::unique_lock<std::mutex> ulock(m_taskMutex);
        auto iter = m_taskIdToTaskList.find(taskId);
        DBG_WARN_AND_RETURN_VOID_UNLESS(iter != m_taskIdToTaskList.end(), L"目标刚通知了，却不在等待通知的队列中", L"蒋家伟", L"2023-08-17");
        bool success = m_taskIdToNotifiedTaskList.insert(std::make_pair(taskId, std::move(iter->second))).second;
        DBG_WARN_AND_RETURN_VOID_UNLESS(success, L"目标第一次被通知，不应该存在执行的队列中", L"蒋家伟", L"2023-08-17");
        m_taskIdToTaskList.erase(iter);
        ulock.unlock();
    }
    else if (pTaskEventArgs->getEventType() == TaskEventType::TaskNotifiedFail)
    {
        std::unique_lock<std::mutex> ulock(m_taskMutex);
        auto iter = m_taskIdToTaskList.find(taskId);
        DBG_WARN_AND_RETURN_VOID_UNLESS(iter != m_taskIdToTaskList.end(), L"目标刚通知了，却不在等待通知的队列中", L"蒋家伟", L"2023-08-17");
        m_taskIdToTaskList.erase(iter);
    }
    else
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(false, L"暂不支持其他任务类型", L"蒋家伟", L"2023-08-17");
    }
}

/**********************************************任务组专用**************************************/
std::vector<TaskId> jsdk::TaskManager::splitTaskGroup(TaskGroup * pTaskGroup)
{
    std::vector<TaskId> res;
    DBG_WARN_AND_RETURN_UNLESS(pTaskGroup, res, L"待拆分的任务组无效", L"蒋家伟", L"2023-07-31");
    std::vector<OwnerPtr<ITask>> allTask = pTaskGroup->transformOwnShip();

    {
        std::unique_lock<std::mutex> ulock(m_taskMutex);
        for (auto& iter : allTask)
        {
            DBG_WARN_AND_CONTINUE_UNLESS(iter, L"任务组中存在无效的任务", L"蒋家伟", L"2023-07-31");
            res.push_back(iter->getTaskId());
            m_taskIdToNotifiedTaskList.insert(std::make_pair(iter->getTaskId(), std::move(iter)));
        }

        // 从子类往父类转换是安全的
        const auto& iter = m_taskIdToTaskList.find(static_cast<ITask*>(pTaskGroup)->getTaskId());
        DBG_WARN_AND_RETURN_UNLESS(iter != m_taskIdToTaskList.end(), res, L"任务组在拆分的过程中，任务组ID消失了", L"蒋家伟", L"2023-08-10");
        m_taskIdToTaskList.erase(iter);
        ulock.unlock();
    }

    return res;
}

ITask* jsdk::TaskManager::getTaskFWByTaskId(const TaskId & taskId)
{
    auto& iter = m_taskIdToTaskList.find(taskId);
    if (iter != m_taskIdToTaskList.end())
    {
        return iter->second.get();
    }
    return nullptr;
}

const ITask * jsdk::TaskManager::getTaskByTaskId(const TaskId & taskId) const
{
    const auto& iter = m_taskIdToTaskList.find(taskId);
    if (iter != m_taskIdToTaskList.end())
    {
        return iter->second.get();
    }
    return nullptr;
}
/**********************************************任务组专用**************************************/
